Step 2: Evaluate output
include_graphics("prsice_images/TERRE_PRSice_BARPLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_HIGH-RES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_QUANTILES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_BARPLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_HIGH-RES_PLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_QUANTILES_PLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_BARPLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_HIGH-RES_PLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_QUANTILES_PLOT_2022-10-04.png")

Plotting PRSice Data on my own
library(ggnewscale)
prsice_male_meta <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.prsice")
ggplot(prsice_male_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
geom_point() +
scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
theme_minimal()

prsice_female_meta <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.prsice")
ggplot(prsice_female_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
geom_point() +
scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
theme_minimal()

prsice_meta <- fread("prsice_data/TERRE_PRSice.prsice")
ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
geom_point(data = prsice_female_meta, size = 1) +
scale_color_gradient(low = "lightpink4", high = "lightpink") +
labs(color = bquote("Female log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "lightblue4", high = "lightblue") +
labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Male log"["10"] ~ "(P)")) +
theme_minimal() +
theme(legend.position = "top")

ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
geom_point(data = prsice_female_meta, size = 1) +
scale_color_gradient(low = "lightpink4", high = "lightpink") +
labs(color = bquote("Female log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "lightblue4", high = "lightblue") +
labs(color = bquote("Male log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "gray40", high = "gray80") +
labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Cross-sex -log"["10"] ~ "(P)")) +
theme_minimal() +
theme(legend.position = "top")

Step 3 run linear model at different thresholds for SNP inclusion
This is updated to recently processed DNAm Data 20 outliers in DNAm removed:
load("/home1/NEURO/SHARE_DECIPHER/processed_DNAm_data/2022/TERRE_processed_2022/1-TERRE_RG_filtered.RData") #PD_RG_filtered
# Assign genotyping ID to data
original_covars <- fread("/home1/NEURO/SHARE_DECIPHER/terre_meta_master.csv")[, .(patient, IID = gsub("_PAE.*", "", IID))]
betas_combat <- minfi::getBeta(PD_RG_filtered)
colnames(betas_combat) <- original_covars$IID[match(colnames(betas_combat), original_covars$patient)]
betas_combat <- betas_combat[, colnames(betas_combat) %in% covariate$IID]
Let’s check how the data looks for the first 5 subjects:
ggplot(betas_combat[, 1:5] %>% as.data.table(keep.rownames = T) %>% melt(id.vars = "rn", value.name = "betas", variable.name = "subject"), aes(betas, color = subject))+
geom_density()

Match DNA, PRS, and metadata @TODO fix this after update of PRS etc.
prsice_best <- fread("prsice_data/TERRE_PRSice.best")[match(colnames(betas_combat), IID,nomatch=0),.(best=PRS)]
prsice_all <- cbind(
fread("prsice_data/TERRE_PRSice.all_score")[match(colnames(betas_combat), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
prsice_best
)
covariate <- covariate[match(colnames(betas_combat), IID)]
all(covariate$IID == colnames(betas_combat))
[1] TRUE
all(covariate$IID == prsice_all$IID)
[1] TRUE
covariate_male <- covariate[sex == 1] %>% select(-sex)
betas_male <- betas_combat[, covariate_male$IID]
prsice_male_best <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.best")[match(colnames(betas_male), IID,nomatch=0),.(best=PRS)]
prsice_male_all <- cbind(
fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.all_score")[match(colnames(betas_male), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
prsice_male_best
)
covariate_male <- covariate_male[match(colnames(betas_male), IID,nomatch=0)]
all(covariate_male$IID == colnames(betas_male))
[1] TRUE
all(covariate_male$IID == prsice_male_all$IID)
[1] TRUE
prsice_female_best <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.best")
covariate_female <- covariate[sex == 0] %>% select(-sex) %>% filter(IID %in% prsice_female_best$IID)
betas_female <- betas_combat[, covariate_female$IID]
prsice_female_best <- prsice_female_best[match(colnames(betas_female), IID,nomatch=0),.(best=PRS)]
prsice_female_all <- cbind(
fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.all_score")[match(colnames(betas_female), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
prsice_female_best
)
covariate_female <- covariate_female[match(colnames(betas_female), IID,nomatch=0)]
all(covariate_female$IID == colnames(betas_female))
[1] TRUE
all(covariate_female$IID == prsice_female_all$IID)
[1] TRUE
Run limma
mvalues <- lumi::beta2m(betas_combat)
prs_mat <- prsice_all[, -c(1, 2)]
cov_mat <- covariate[, -c(1, 2)]
mvalues_male <- lumi::beta2m(betas_male)
prs_mat_male <- prsice_male_all[, -c(1, 2)]
cov_mat_male <- covariate_male[, -c(1, 2)]
mvalues_female <- lumi::beta2m(betas_female)
prs_mat_female <- prsice_female_all[, -c(1, 2)]
cov_mat_female <- covariate_female[, -c(1, 2)]
registerDoParallel(ncol(prs_mat) / 4)
hits <- foreach(prs_thresh = colnames(prs_mat)) %dopar% {
design_prs <- model.matrix(~., data = cbind(prs_mat[, ..prs_thresh], cov_mat))
prs_fit <- lmFit(mvalues, design_prs)
prs_fit <- eBayes(prs_fit)
topTable(prs_fit, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues))
}
names(hits) <- colnames(prs_mat)
hits_by_thresh_bonf <- rbindlist(hits, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_male) / 4)
hits_male <- foreach(prs_thresh = colnames(prs_mat_male)) %dopar% {
design_prs_male <- model.matrix(~., data = cbind(prs_mat_male[, ..prs_thresh], cov_mat_male))
prs_fit_male <- lmFit(mvalues_male, design_prs_male)
prs_fit_male <- eBayes(prs_fit_male)
topTable(prs_fit_male, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_male))
}
names(hits_male) <- colnames(prs_mat_male)
hits_by_thresh_bonf_male <- rbindlist(hits_male, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_female) / 4)
hits_female <- foreach(prs_thresh = colnames(prs_mat_female)) %dopar% {
design_prs_female <- model.matrix(~., data = cbind(prs_mat_female[, ..prs_thresh], cov_mat_female))
prs_fit_female <- lmFit(mvalues_female, design_prs_female)
prs_fit_female <- eBayes(prs_fit_female)
topTable(prs_fit_female, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_female))
}
names(hits_female) <- colnames(prs_mat_female)
hits_by_thresh_bonf_female <- rbindlist(hits_female, idcol = "threshold", fill = TRUE)
Plotting EWAS vs Threshold Experiment by Sex
to_plot <- rbind(
hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
hits_by_thresh_bonf_male[, .(hits = .N, Sex = "Male"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
hits_by_thresh_bonf_female[, .(hits = .N, Sex = "Female"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0"))
) %>% mutate(Sex = factor(Sex, levels = c("Cross-sex", "Male", "Female")))
plot_pos <- position_dodge(width = 1)
ggplot(to_plot, aes(threshold, hits, fill = Sex, label = hits)) +
geom_text(position = plot_pos, vjust = -0.25) +
geom_col(position = plot_pos) +
labs(x = "GWAS P Value Threshold", y = "EWAS Hits") +
scale_fill_manual(values = c("grey80", "lightblue", "lightpink")) +
theme_minimal()

hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold]
hits_by_thresh_bonf_male[, .(hits = .N), by = threshold]
hits_by_thresh_bonf_female[, .(hits = .N), by = threshold]
display_venn <- function(x, ...) {
library(VennDiagram)
grid.newpage()
venn_object <- venn.diagram(x, filename = NULL, ...)
grid.draw(venn_object)
}
display_venn(list(`Cross-sex` = hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID, Male = hits_by_thresh_bonf_male[threshold == "Pt_5e-08"]$ID, Female = hits_by_thresh_bonf_female[threshold == "Pt_5e-08"]$ID), fill = c("gray80", "lightblue", "lightpink"))

male_ids <- hits_by_thresh_bonf_male[threshold == "Pt_5e-08"]$ID
cross_ids <- hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID
male_ids[!male_ids %in% cross_ids]
character(0)
library(missMethyl)
gometh(hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID, array.type = "EPIC", all.cpg = rownames(mvalues))
get_full_fit <- function(prs_mat,cov_mat,mvalues){
top_design_prs <- model.matrix(~., data = cbind(prs_mat[, `Pt_5e-08`], cov_mat))
top_prs_fit <- lmFit(mvalues, top_design_prs)
top_prs_fit <- eBayes(top_prs_fit)
top_prs_hits <- topTable(top_prs_fit, coef = 2, adjust.method = "bonf", number = Inf, genelist = rownames(mvalues))
}
top_prs_hits <- get_full_fit(prs_mat,cov_mat,mvalues)
top_male_prs_hits <- get_full_fit(prs_mat_male, cov_mat_male, mvalues_male)
top_female_prs_hits <- get_full_fit(prs_mat_female, cov_mat_female, mvalues_female)
save(list=c("top_prs_hits","top_male_prs_hits","top_female_prs_hits"),file="prs_nalls_cross_w_sex_stratified.RData")
manifest <- IlluminaHumanMethylationEPICanno.ilm10b4.hg19::Other %>%
as.data.frame() %>%
rownames_to_column(var = "name")
prs_annot <- data.table(top_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_male <- data.table(top_male_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_female<- data.table(top_female_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
plot_prs_hits <- function(prs_annot,label_color){
ggplot(prs_annot, aes(logFC, -log10(P.Value))) +
geom_point() +
geom_point(
data = subset(prs_annot, adj.P.Val < 0.05 & abs(logFC) > 0.03),
color = label_color,
mapping = aes(logFC, -log10(P.Value))
) +
geom_hline(
linetype = "dashed",
yintercept = min(-log10(prs_annot$P.Value[prs_annot$adj.P.Val < 0.05]))
) +
geom_vline(linetype = "dashed", xintercept = 0.03) +
geom_vline(linetype = "dashed", xintercept = -0.03) +
geom_text_repel(
data = prs_annot %>% filter(abs(logFC) > 0.03 & adj.P.Val < 0.05),
color = "dodgerblue",
mapping = aes(logFC, -log10(P.Value), label = ifelse(gene != "", gene, ID)),
size = 3,
max.overlaps = 20
) +
labs(y = bquote("log"[10] ~ "(P)"), x = quote(Delta ~ "M" ~ Methylation)) +
theme_minimal()
}
plot_prs_hits(prs_annot,"gray40")

plot_prs_hits(prs_annot_male,"lightblue")

plot_prs_hits(prs_annot_female,"pink")

Manhattan plot vs GWAS manhattan plot
library(qqman)
cpg_pos <- IlluminaHumanMethylationEPICanno.ilm10b4.hg19::Locations %>%
as.data.frame() %>%
rownames_to_column(var = "name")
copy_annot <- prs_annot[cpg_pos, on = c(ID = "name")] %>%
mutate(chr = as.numeric(recode(gsub("chr", "", chr),X="23",Y="24")))
to_plot <- copy_annot[, .(SNP = gene, CHR = chr, BP = pos, P = P.Value, FDR = adj.P.Val)][!is.na(P)]
manhattan(to_plot,
annotatePval = max(to_plot[FDR < 0.05]$P),
annotateTop = TRUE,
genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
suggestiveline = FALSE
)
manhattan(to_plot[CHR == 17],
annotatePval = max(to_plot[FDR < 0.05]$P),
annotateTop = FALSE,
genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
suggestiveline = FALSE
)
qq(to_plot$P)
GWAS <- fread("~/nalls_PD.QC.gz")
manhattan(GWAS,
annotatePval = 5e-8,
bp = "POS",
p = "p",
suggestiveline = FALSE
)
DMRs
dmr_males <- run_dmrcate(prs_mat_male,cov_mat_male,mvalues_male)
Your contrast returned 59 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_males <- run_dmrcate(prs_mat_male,cov_mat_male,mvalues_male)
Your contrast returned 59 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_female <- run_dmrcate(prs_mat_female,cov_mat_female,mvalues_female)
Your contrast returned 41 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
annotation <- minfi::getAnnotation(IlluminaHumanMethylationEPICanno.ilm10b4.hg19)
Plotting all DMRs
get_dmr_effects <- function(dmr, limma_res,mvalues) {
dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
cpgs <- as.data.table(annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ])
res <- limma_res[cpgs,on=c("ID"="Name"),nomatch=0 ]
dmr_1 <- as.data.frame(res[!is.na(res$logFC), ])
dmr_methy <- reshape2::melt(lumi::m2beta(mvalues[dmr_1$ID, ]), stringsAsFactors = FALSE)
to_plot <- merge(dmr_1, dmr_methy, by.x = "ID", by.y = "Var1")
to_plot$DMR <- dmr
to_plot
}
get_dmr_res <- function(dmr, limma_res) {
dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
cpgs <- annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ]
res <- cbind(cpgs, limma_res[cpgs$Name, ])
res$DMR <- dmr
return(res)
}
plot_dmrs <- function(dmr_res,limma_res,prs_mat, mvalues, case_control) {
to_plot <- rbindlist(lapply(dmr_res$coord, function(dmr) get_dmr_effects(dmr, limma_res,mvalues))) %>%
mutate(SCORE1_AVG = scale(prs_mat[match(Var2,IDs$IID),`Pt_5e-08`]),PD = PD[match(Var2,IID)]$PD) %>%
filter(!is.na(SCORE1_AVG))
for(cur_dmr in unique(to_plot$DMR)){
cur_plot <- to_plot[DMR == cur_dmr]
p1 <- ggplot(cur_plot , aes(pos, value, color = SCORE1_AVG)) +
geom_point() +
scale_color_gradient(low = rev(case_control)[1], high = rev(case_control)[2]) +
theme_minimal() +
labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "Normalized PD PRS")+
theme(axis.text.x = element_text(angle = 90))
p2 <- ggplot(cur_plot %>% mutate(PD = ifelse(PD == 1, "CASE", "CONTROL")), aes(factor(pos), value, color = PD)) +
geom_boxplot(position = position_dodge(0.75)) +
scale_color_manual(values = case_control) +
theme_minimal() +
stat_summary(aes(group = PD), fun = mean, geom = "line") +
labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "PD status") +
theme(axis.text.x = element_text(angle = 90))
print(p1)
print(p2)
}
}
plot_dmrs(dmr_cross, prs_annot, prs_mat,mvalues, rev(c("gray80", "gray40")))




















plot_dmrs(dmr_males,prs_annot_male,prs_mat_male, mvalues_male,rev(c("light blue", "lightblue4")))




















plot_dmrs(dmr_female, prs_annot_female, prs_mat_female, mvalues_female,rev(c("lightpink", "lightpink4")))












dmr_cross
dmr_males
dmr_female
LS0tCnRpdGxlOiAiUFJTaWNlMiBEZXZlbG9wbWVudCBvZiByaXNrIHNjb3JlIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShrbml0cikKbGlicmFyeShsaW1tYSkKbGlicmFyeShmb3JlYWNoKQpsaWJyYXJ5KGRvUGFyYWxsZWwpClN5cy5zZXRsb2NhbGUoIkxDX01FU1NBR0VTIiwgImVuX1VTLnV0ZjgiKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBTdGVwIDA6IFByZXBhcmUgY292YXJpYXRlcyBhbmQgaW5wdXQgZmlsZXMKYGBge3J9CklEcyA8LSBmcmVhZCgifi9nZW5vdHlwZV9xYy9URVJSRV9RQy9hbGxfaW1wdXRlZF9yMl8zMF9yc2lkX2hhcmRfY2FsbC5mYW0iKVssIC4oRklEID0gVjEsIElJRCA9IFYyKV0KcHJzaWNlX2NvdiA8LSBmcmVhZCgicHJzaWNlX2Nvdl9hbmRfc3RhdHVzX212YWx1ZXMudHh0IikKcHJzaWNlX2NvdiA8LSBwcnNpY2VfY292W21hdGNoKElEcyRJSUQscHJzaWNlX2NvdiRJSUQpXQphbGwoSURzJElJRCA9PXByc2ljZV9jb3YkSUlEKQpjb3ZhcmlhdGUgPC0gY2JpbmQoSURzLCBwcnNpY2VfY292WywtYygxNiwxNywxOCldKQoKUEQgPC0gY2JpbmQoSURzLHByc2ljZV9jb3ZbLDE2XSkKCmhlYWQoY292YXJpYXRlKQpoZWFkKFBEKQpmd3JpdGUobmEub21pdChQRCksICJURVJSRS5waGVubyIsIHNlcCA9ICJcdCIpCmZ3cml0ZShuYS5vbWl0KGNvdmFyaWF0ZSksICJURVJSRS5jb3ZhcmlhdGUiLCBzZXAgPSAiXHQiKQpgYGAKYGBge3J9CmNvdmFyaWF0ZQpgYGAKCgojIFN0ZXAgMTogUnVuIFBSU2ljZS0yIG9uIE5hbGxzIGV0IGFsIDIwMTkgU3Vtc3RhdHMKYGBge2Jhc2gsZXZhbD1GQUxTRX0KUnNjcmlwdCAvaG9tZTEvTkVVUk8vY2FzYXp6YS9QUlNpY2UuUiBcCiAgICAtLXByc2ljZSAvaG9tZTEvTkVVUk8vY2FzYXp6YS9QUlNpY2VfbGludXhcCiAgICAtLWJhc2UgL2hvbWUxL05FVVJPL2Nhc2F6emEvbmFsbHNfUEQuUUMuZ3pcCiAgICAtLWJhc2UtaW5mbyBJTkZPOjAuOCBcCiAgICAtLWJhc2UtbWFmIE1BRjowLjAxIFwKICAgIC0tY292IFRFUlJFLmNvdmFyaWF0ZSBcCiAgICAtLWJpbmFyeS10YXJnZXQgVFwKICAgIC0tYmV0YSAgXAogICAgLS1sZCAvaG9tZTEvTkVVUk8vY2FzYXp6YS8xMDAwR19wbGluay9FVVJfcGhhc2UzICBcCiAgICAtLW91dCBURVJSRV9QUlNpY2UgXAogICAgLXEgNVwKICAgIC0tYWxsLXNjb3JlXAogICAgLS1waGVubyBURVJSRS5waGVubyBcCiAgICAtLXNucCBTTlAgXAogICAgLS1zdGF0IGIgXAogICAgLS1wdmFsdWUgcFwKICAgIC0tdGFyZ2V0IC9ob21lMS9ORVVSTy9jYXNhenphL2dlbm90eXBlX3FjL1RFUlJFX1FDL2FsbF9pbXB1dGVkX3IyXzMwX3JzaWRfaGFyZF9jYWxsIFwKICAgIC0tdGhyZWFkIDMyCmBgYAojIFN0ZXAgMjogRXZhbHVhdGUgb3V0cHV0CmBgYHtyLCBvdXQud2lkdGg9IjQwMHB4In0KaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfQkFSUExPVF8yMDIyLTA2LTMwLnBuZyIpCmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX0hJR0gtUkVTX1BMT1RfMjAyMi0wNi0zMC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9RVUFOVElMRVNfUExPVF8yMDIyLTA2LTMwLnBuZyIpCgppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX0JBUlBMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX0hJR0gtUkVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX1FVQU5USUxFU19QTE9UXzIwMjItMTAtMDQucG5nIikKCmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX25hbGxzX2ZlbWFsZV9CQVJQTE9UXzIwMjItMTAtMDQucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfZmVtYWxlX0hJR0gtUkVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGVfUVVBTlRJTEVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQpgYGAKIyMgUGxvdHRpbmcgUFJTaWNlIERhdGEgb24gbXkgb3duCmBgYHtyfQpsaWJyYXJ5KGdnbmV3c2NhbGUpCnByc2ljZV9tYWxlX21ldGEgPC0gZnJlYWQoInByc2ljZV9uYWxsc19tYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX21hbGUucHJzaWNlIikKZ2dwbG90KHByc2ljZV9tYWxlX21ldGFbVGhyZXNob2xkIDw9IDAuNV0sIGFlcyhUaHJlc2hvbGQsIE51bV9TTlAsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKDAsIDFlNSwgMi41ZTQpLCBzZXEoMmU1LCA2ZTUsIDFlNSkpKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwcnNpY2VfZmVtYWxlX21ldGEgPC0gZnJlYWQoInByc2ljZV9uYWxsc19mZW1hbGVfZGF0YS9URVJSRV9QUlNpY2VfbmFsbHNfZmVtYWxlLnByc2ljZSIpCmdncGxvdChwcnNpY2VfZmVtYWxlX21ldGFbVGhyZXNob2xkIDw9IDAuNV0sIGFlcyhUaHJlc2hvbGQsIE51bV9TTlAsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKDAsIDFlNSwgMi41ZTQpLCBzZXEoMmU1LCA2ZTUsIDFlNSkpKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwcnNpY2VfbWV0YSA8LSBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLnByc2ljZSIpCmdncGxvdChtYXBwaW5nID0gYWVzKFRocmVzaG9sZCwgUjIsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9mZW1hbGVfbWV0YSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRwaW5rNCIsIGhpZ2ggPSAibGlnaHRwaW5rIikgKwogIGxhYnMoY29sb3IgPSBicXVvdGUoIkZlbWFsZSBsb2ciWyIxMCJdIH4gIihQKSIpKSArCiAgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9tYWxlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZTQiLCBoaWdoID0gImxpZ2h0Ymx1ZSIpICsKICBsYWJzKHkgPSBicXVvdGUoIlIiXjIpLCB4ID0gIkdXQVMgUC1WYWx1ZSBUaHJlc2hvbGQiLCBjb2xvciA9IGJxdW90ZSgiTWFsZSBsb2ciWyIxMCJdIH4gIihQKSIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKZ2dwbG90KG1hcHBpbmcgPSBhZXMoVGhyZXNob2xkLCBSMiwgY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcHJzaWNlX2ZlbWFsZV9tZXRhLCBzaXplID0gMSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJsaWdodHBpbms0IiwgaGlnaCA9ICJsaWdodHBpbmsiKSArCiAgbGFicyhjb2xvciA9IGJxdW90ZSgiRmVtYWxlIGxvZyJbIjEwIl0gfiAiKFApIikpICsKICBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcHJzaWNlX21hbGVfbWV0YSwgc2l6ZSA9IDEsIGFlcyhjb2xvciA9IC1sb2cxMChQKSkpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRibHVlNCIsIGhpZ2ggPSAibGlnaHRibHVlIikgKwogIGxhYnMoY29sb3IgPSBicXVvdGUoIk1hbGUgbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwcnNpY2VfbWV0YSwgc2l6ZSA9IDEsIGFlcyhjb2xvciA9IC1sb2cxMChQKSkpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiZ3JheTQwIiwgaGlnaCA9ICJncmF5ODAiKSArCiAgbGFicyh5ID0gYnF1b3RlKCJSIl4yKSwgeCA9ICJHV0FTIFAtVmFsdWUgVGhyZXNob2xkIiwgY29sb3IgPSBicXVvdGUoIkNyb3NzLXNleCAtbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKIyBTdGVwIDMgcnVuIGxpbmVhciBtb2RlbCBhdCBkaWZmZXJlbnQgdGhyZXNob2xkcyBmb3IgU05QIGluY2x1c2lvbgpUaGlzIGlzIHVwZGF0ZWQgdG8gcmVjZW50bHkgcHJvY2Vzc2VkIEROQW0gRGF0YSAyMCBvdXRsaWVycyBpbiBETkFtIHJlbW92ZWQ6CmBgYHtyfQpsb2FkKCIvaG9tZTEvTkVVUk8vU0hBUkVfREVDSVBIRVIvcHJvY2Vzc2VkX0ROQW1fZGF0YS8yMDIyL1RFUlJFX3Byb2Nlc3NlZF8yMDIyLzEtVEVSUkVfUkdfZmlsdGVyZWQuUkRhdGEiKSAjUERfUkdfZmlsdGVyZWQKIyBBc3NpZ24gZ2Vub3R5cGluZyBJRCB0byBkYXRhCm9yaWdpbmFsX2NvdmFycyA8LSBmcmVhZCgiL2hvbWUxL05FVVJPL1NIQVJFX0RFQ0lQSEVSL3RlcnJlX21ldGFfbWFzdGVyLmNzdiIpWywgLihwYXRpZW50LCBJSUQgPSBnc3ViKCJfUEFFLioiLCAiIiwgSUlEKSldCmJldGFzX2NvbWJhdCA8LSBtaW5maTo6Z2V0QmV0YShQRF9SR19maWx0ZXJlZCkKY29sbmFtZXMoYmV0YXNfY29tYmF0KSA8LSBvcmlnaW5hbF9jb3ZhcnMkSUlEW21hdGNoKGNvbG5hbWVzKGJldGFzX2NvbWJhdCksIG9yaWdpbmFsX2NvdmFycyRwYXRpZW50KV0KYmV0YXNfY29tYmF0IDwtIGJldGFzX2NvbWJhdFssIGNvbG5hbWVzKGJldGFzX2NvbWJhdCkgJWluJSBjb3ZhcmlhdGUkSUlEXQpgYGAKTGV0J3MgY2hlY2sgaG93IHRoZSBkYXRhIGxvb2tzIGZvciB0aGUgZmlyc3QgNSBzdWJqZWN0czoKYGBge3J9CmdncGxvdChiZXRhc19jb21iYXRbLCAxOjVdICU+JSBhcy5kYXRhLnRhYmxlKGtlZXAucm93bmFtZXMgPSBUKSAlPiUgbWVsdChpZC52YXJzID0gInJuIiwgdmFsdWUubmFtZSA9ICJiZXRhcyIsIHZhcmlhYmxlLm5hbWUgPSAic3ViamVjdCIpLCBhZXMoYmV0YXMsIGNvbG9yID0gc3ViamVjdCkpKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKIyMjIE1hdGNoIEROQSwgUFJTLCBhbmQgbWV0YWRhdGEgQFRPRE8gZml4IHRoaXMgYWZ0ZXIgdXBkYXRlIG9mIFBSUyBldGMuCmBgYHtyfQpwcnNpY2VfYmVzdCA8LSBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLmJlc3QiKVttYXRjaChjb2xuYW1lcyhiZXRhc19jb21iYXQpLCBJSUQsbm9tYXRjaD0wKSwuKGJlc3Q9UFJTKV0KcHJzaWNlX2FsbCA8LSBjYmluZCgKICBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLmFsbF9zY29yZSIpW21hdGNoKGNvbG5hbWVzKGJldGFzX2NvbWJhdCksIElJRCxub21hdGNoPTApLCAuKEZJRCwgSUlELCBgUHRfNWUtMDhgLCBgUHRfNS4wMDVlLTA1YCwgYFB0XzAuMDAwMTAwMDVgLCBgUHRfMC4wMDEwMDAwNWAsIGBQdF8wLjAxMDE1MDFgLCBgUHRfMC4xYCwgYFB0XzAuMmAsIGBQdF8wLjNgLCBgUHRfMC40YCwgYFB0XzAuNWAsIGBQdF8xYCldLAogIHByc2ljZV9iZXN0CikKY292YXJpYXRlIDwtIGNvdmFyaWF0ZVttYXRjaChjb2xuYW1lcyhiZXRhc19jb21iYXQpLCBJSUQpXQphbGwoY292YXJpYXRlJElJRCA9PSBjb2xuYW1lcyhiZXRhc19jb21iYXQpKQphbGwoY292YXJpYXRlJElJRCA9PSBwcnNpY2VfYWxsJElJRCkKCmNvdmFyaWF0ZV9tYWxlIDwtIGNvdmFyaWF0ZVtzZXggPT0gMV0gJT4lIHNlbGVjdCgtc2V4KQpiZXRhc19tYWxlIDwtIGJldGFzX2NvbWJhdFssIGNvdmFyaWF0ZV9tYWxlJElJRF0KcHJzaWNlX21hbGVfYmVzdCA8LSBmcmVhZCgicHJzaWNlX25hbGxzX21hbGVfZGF0YS9URVJSRV9QUlNpY2VfbmFsbHNfbWFsZS5iZXN0IilbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCxub21hdGNoPTApLC4oYmVzdD1QUlMpXQpwcnNpY2VfbWFsZV9hbGwgPC0gY2JpbmQoCiAgZnJlYWQoInByc2ljZV9uYWxsc19tYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX21hbGUuYWxsX3Njb3JlIilbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCxub21hdGNoPTApLCAuKEZJRCwgSUlELCBgUHRfNWUtMDhgLCBgUHRfNS4wMDVlLTA1YCwgYFB0XzAuMDAwMTAwMDVgLCBgUHRfMC4wMDEwMDAwNWAsIGBQdF8wLjAxMDE1MDFgLCBgUHRfMC4xYCwgYFB0XzAuMmAsIGBQdF8wLjNgLCBgUHRfMC40YCwgYFB0XzAuNWAsIGBQdF8xYCldLAogIHByc2ljZV9tYWxlX2Jlc3QKKQpjb3ZhcmlhdGVfbWFsZSA8LSBjb3ZhcmlhdGVfbWFsZVttYXRjaChjb2xuYW1lcyhiZXRhc19tYWxlKSwgSUlELG5vbWF0Y2g9MCldCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gY29sbmFtZXMoYmV0YXNfbWFsZSkpCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gcHJzaWNlX21hbGVfYWxsJElJRCkKCnByc2ljZV9mZW1hbGVfYmVzdCA8LSBmcmVhZCgicHJzaWNlX25hbGxzX2ZlbWFsZV9kYXRhL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGUuYmVzdCIpCmNvdmFyaWF0ZV9mZW1hbGUgPC0gY292YXJpYXRlW3NleCA9PSAwXSAlPiUgc2VsZWN0KC1zZXgpICU+JSBmaWx0ZXIoSUlEICVpbiUgcHJzaWNlX2ZlbWFsZV9iZXN0JElJRCkKYmV0YXNfZmVtYWxlIDwtIGJldGFzX2NvbWJhdFssIGNvdmFyaWF0ZV9mZW1hbGUkSUlEXQpwcnNpY2VfZmVtYWxlX2Jlc3QgPC0gcHJzaWNlX2ZlbWFsZV9iZXN0W21hdGNoKGNvbG5hbWVzKGJldGFzX2ZlbWFsZSksIElJRCxub21hdGNoPTApLC4oYmVzdD1QUlMpXQpwcnNpY2VfZmVtYWxlX2FsbCA8LSBjYmluZCgKICBmcmVhZCgicHJzaWNlX25hbGxzX2ZlbWFsZV9kYXRhL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGUuYWxsX3Njb3JlIilbbWF0Y2goY29sbmFtZXMoYmV0YXNfZmVtYWxlKSwgSUlELG5vbWF0Y2g9MCksIC4oRklELCBJSUQsIGBQdF81ZS0wOGAsIGBQdF81LjAwNWUtMDVgLCBgUHRfMC4wMDAxMDAwNWAsIGBQdF8wLjAwMTAwMDA1YCwgYFB0XzAuMDEwMTUwMWAsIGBQdF8wLjFgLCBgUHRfMC4yYCwgYFB0XzAuM2AsIGBQdF8wLjRgLCBgUHRfMC41YCwgYFB0XzFgKV0sCiAgcHJzaWNlX2ZlbWFsZV9iZXN0CikKY292YXJpYXRlX2ZlbWFsZSA8LSBjb3ZhcmlhdGVfZmVtYWxlW21hdGNoKGNvbG5hbWVzKGJldGFzX2ZlbWFsZSksIElJRCxub21hdGNoPTApXQphbGwoY292YXJpYXRlX2ZlbWFsZSRJSUQgPT0gY29sbmFtZXMoYmV0YXNfZmVtYWxlKSkKYWxsKGNvdmFyaWF0ZV9mZW1hbGUkSUlEID09IHByc2ljZV9mZW1hbGVfYWxsJElJRCkKCgpgYGAKIyMjIFJ1biBsaW1tYQoKYGBge3J9Cm12YWx1ZXMgPC0gbHVtaTo6YmV0YTJtKGJldGFzX2NvbWJhdCkKcHJzX21hdCA8LSBwcnNpY2VfYWxsWywgLWMoMSwgMildCmNvdl9tYXQgPC0gY292YXJpYXRlWywgLWMoMSwgMildCgptdmFsdWVzX21hbGUgPC0gbHVtaTo6YmV0YTJtKGJldGFzX21hbGUpCnByc19tYXRfbWFsZSA8LSBwcnNpY2VfbWFsZV9hbGxbLCAtYygxLCAyKV0KY292X21hdF9tYWxlIDwtIGNvdmFyaWF0ZV9tYWxlWywgLWMoMSwgMildCgptdmFsdWVzX2ZlbWFsZSA8LSBsdW1pOjpiZXRhMm0oYmV0YXNfZmVtYWxlKQpwcnNfbWF0X2ZlbWFsZSA8LSBwcnNpY2VfZmVtYWxlX2FsbFssIC1jKDEsIDIpXQpjb3ZfbWF0X2ZlbWFsZSA8LSBjb3ZhcmlhdGVfZmVtYWxlWywgLWMoMSwgMildCmBgYAoKYGBge3J9CnJlZ2lzdGVyRG9QYXJhbGxlbChuY29sKHByc19tYXQpIC8gNCkKaGl0cyA8LSBmb3JlYWNoKHByc190aHJlc2ggPSBjb2xuYW1lcyhwcnNfbWF0KSkgJWRvcGFyJSB7CiAgZGVzaWduX3BycyA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0WywgLi5wcnNfdGhyZXNoXSwgY292X21hdCkpCiAgcHJzX2ZpdCA8LSBsbUZpdChtdmFsdWVzLCBkZXNpZ25fcHJzKQogIHByc19maXQgPC0gZUJheWVzKHByc19maXQpCiAgdG9wVGFibGUocHJzX2ZpdCwgY29lZiA9IDIsIGFkanVzdC5tZXRob2QgPSAiYm9uZiIsIHAudmFsdWUgPSAwLjA1LCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlcykpCn0KbmFtZXMoaGl0cykgPC0gY29sbmFtZXMocHJzX21hdCkKaGl0c19ieV90aHJlc2hfYm9uZiA8LSByYmluZGxpc3QoaGl0cywgaWRjb2wgPSAidGhyZXNob2xkIiwgZmlsbCA9IFRSVUUpCgpyZWdpc3RlckRvUGFyYWxsZWwobmNvbChwcnNfbWF0X21hbGUpIC8gNCkKaGl0c19tYWxlIDwtIGZvcmVhY2gocHJzX3RocmVzaCA9IGNvbG5hbWVzKHByc19tYXRfbWFsZSkpICVkb3BhciUgewogIGRlc2lnbl9wcnNfbWFsZSA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0X21hbGVbLCAuLnByc190aHJlc2hdLCBjb3ZfbWF0X21hbGUpKQogIHByc19maXRfbWFsZSA8LSBsbUZpdChtdmFsdWVzX21hbGUsIGRlc2lnbl9wcnNfbWFsZSkKICBwcnNfZml0X21hbGUgPC0gZUJheWVzKHByc19maXRfbWFsZSkKICB0b3BUYWJsZShwcnNfZml0X21hbGUsIGNvZWYgPSAyLCBhZGp1c3QubWV0aG9kID0gImJvbmYiLCBwLnZhbHVlID0gMC4wNSwgbnVtYmVyID0gSW5mLCBnZW5lbGlzdCA9IHJvd25hbWVzKG12YWx1ZXNfbWFsZSkpCn0KbmFtZXMoaGl0c19tYWxlKSA8LSBjb2xuYW1lcyhwcnNfbWF0X21hbGUpCmhpdHNfYnlfdGhyZXNoX2JvbmZfbWFsZSA8LSByYmluZGxpc3QoaGl0c19tYWxlLCBpZGNvbCA9ICJ0aHJlc2hvbGQiLCBmaWxsID0gVFJVRSkKCnJlZ2lzdGVyRG9QYXJhbGxlbChuY29sKHByc19tYXRfZmVtYWxlKSAvIDQpCmhpdHNfZmVtYWxlIDwtIGZvcmVhY2gocHJzX3RocmVzaCA9IGNvbG5hbWVzKHByc19tYXRfZmVtYWxlKSkgJWRvcGFyJSB7CiAgZGVzaWduX3Byc19mZW1hbGUgPC0gbW9kZWwubWF0cml4KH4uLCBkYXRhID0gY2JpbmQocHJzX21hdF9mZW1hbGVbLCAuLnByc190aHJlc2hdLCBjb3ZfbWF0X2ZlbWFsZSkpCiAgcHJzX2ZpdF9mZW1hbGUgPC0gbG1GaXQobXZhbHVlc19mZW1hbGUsIGRlc2lnbl9wcnNfZmVtYWxlKQogIHByc19maXRfZmVtYWxlIDwtIGVCYXllcyhwcnNfZml0X2ZlbWFsZSkKICB0b3BUYWJsZShwcnNfZml0X2ZlbWFsZSwgY29lZiA9IDIsIGFkanVzdC5tZXRob2QgPSAiYm9uZiIsIHAudmFsdWUgPSAwLjA1LCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlc19mZW1hbGUpKQp9Cm5hbWVzKGhpdHNfZmVtYWxlKSA8LSBjb2xuYW1lcyhwcnNfbWF0X2ZlbWFsZSkKaGl0c19ieV90aHJlc2hfYm9uZl9mZW1hbGUgPC0gcmJpbmRsaXN0KGhpdHNfZmVtYWxlLCBpZGNvbCA9ICJ0aHJlc2hvbGQiLCBmaWxsID0gVFJVRSkKCmBgYAoKIyMjIFBsb3R0aW5nIEVXQVMgdnMgVGhyZXNob2xkIEV4cGVyaW1lbnQgYnkgU2V4CmBgYHtyfQp0b19wbG90IDwtIHJiaW5kKAogIGhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0gJT4lCiAgICBtdXRhdGUodGhyZXNob2xkID0gcmVjb2RlX2ZhY3Rvcih0aHJlc2hvbGQsIGBQdF8wLjAyMTkwMDFgID0gIjAuMDIxOSIsIGBQdF81ZS0wOGAgPSAiNWUtOCIsIGBQdF81LjAwNWUtMDVgID0gIjVlLTUiLCBgUHRfMC4wMDAxMDAwNWAgPSAiMWUtNCIsIGBQdF8wLjAwMTAwMDA1YCA9ICIxZS0zIiwgYFB0XzAuMDEwMTUwMWAgPSAiMWUtMiIsIGBQdF8wLjFgID0gIjAuMSIsIGBQdF8wLjJgID0gIjAuMiIsIGBQdF8wLjNgID0gIjAuMyIsIGBQdF8wLjRgID0gIjAuNCIsIGBQdF8wLjVgID0gIjAuNSIsIGBQdF8xYCA9ICIxLjAiKSksCiAgaGl0c19ieV90aHJlc2hfYm9uZl9tYWxlWywgLihoaXRzID0gLk4sIFNleCA9ICJNYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKSwKICBoaXRzX2J5X3RocmVzaF9ib25mX2ZlbWFsZVssIC4oaGl0cyA9IC5OLCBTZXggPSAiRmVtYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKQopICU+JSBtdXRhdGUoU2V4ID0gZmFjdG9yKFNleCwgbGV2ZWxzID0gYygiQ3Jvc3Mtc2V4IiwgIk1hbGUiLCAiRmVtYWxlIikpKQpwbG90X3BvcyA8LSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpCmdncGxvdCh0b19wbG90LCBhZXModGhyZXNob2xkLCBoaXRzLCBmaWxsID0gU2V4LCBsYWJlbCA9IGhpdHMpKSArCiAgZ2VvbV90ZXh0KHBvc2l0aW9uID0gcGxvdF9wb3MsIHZqdXN0ID0gLTAuMjUpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBsb3RfcG9zKSArCiAgbGFicyh4ID0gIkdXQVMgUCBWYWx1ZSBUaHJlc2hvbGQiLCB5ID0gIkVXQVMgSGl0cyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKSArCiAgdGhlbWVfbWluaW1hbCgpCmhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9tYWxlWywgLihoaXRzID0gLk4pLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9mZW1hbGVbLCAuKGhpdHMgPSAuTiksIGJ5ID0gdGhyZXNob2xkXQpgYGAKYGBge3J9CmRpc3BsYXlfdmVubiA8LSBmdW5jdGlvbih4LCAuLi4pIHsKICBsaWJyYXJ5KFZlbm5EaWFncmFtKQogIGdyaWQubmV3cGFnZSgpCiAgdmVubl9vYmplY3QgPC0gdmVubi5kaWFncmFtKHgsIGZpbGVuYW1lID0gTlVMTCwgLi4uKQogIGdyaWQuZHJhdyh2ZW5uX29iamVjdCkKfQoKZGlzcGxheV92ZW5uKGxpc3QoYENyb3NzLXNleGAgPSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCwgTWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfbWFsZVt0aHJlc2hvbGQgPT0gIlB0XzVlLTA4Il0kSUQsIEZlbWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfZmVtYWxlW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCksIGZpbGwgPSBjKCJncmF5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKQptYWxlX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mX21hbGVbdGhyZXNob2xkID09ICJQdF81ZS0wOCJdJElECmNyb3NzX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRAptYWxlX2lkc1shbWFsZV9pZHMgJWluJSBjcm9zc19pZHNdCmBgYAoKYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShtaXNzTWV0aHlsKQpnb21ldGgoaGl0c19ieV90aHJlc2hfYm9uZlt0aHJlc2hvbGQgPT0gIlB0XzVlLTA4Il0kSUQsIGFycmF5LnR5cGUgPSAiRVBJQyIsIGFsbC5jcGcgPSByb3duYW1lcyhtdmFsdWVzKSkKYGBgCgpgYGB7cn0KZ2V0X2Z1bGxfZml0IDwtIGZ1bmN0aW9uKHByc19tYXQsY292X21hdCxtdmFsdWVzKXsKICB0b3BfZGVzaWduX3BycyA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0WywgYFB0XzVlLTA4YF0sIGNvdl9tYXQpKQogIHRvcF9wcnNfZml0IDwtIGxtRml0KG12YWx1ZXMsIHRvcF9kZXNpZ25fcHJzKQogIHRvcF9wcnNfZml0IDwtIGVCYXllcyh0b3BfcHJzX2ZpdCkKICB0b3BfcHJzX2hpdHMgPC0gdG9wVGFibGUodG9wX3Byc19maXQsIGNvZWYgPSAyLCBhZGp1c3QubWV0aG9kID0gImJvbmYiLCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlcykpCn0KdG9wX3Byc19oaXRzIDwtIGdldF9mdWxsX2ZpdChwcnNfbWF0LGNvdl9tYXQsbXZhbHVlcykKdG9wX21hbGVfcHJzX2hpdHMgPC0gZ2V0X2Z1bGxfZml0KHByc19tYXRfbWFsZSwgY292X21hdF9tYWxlLCBtdmFsdWVzX21hbGUpCnRvcF9mZW1hbGVfcHJzX2hpdHMgPC0gZ2V0X2Z1bGxfZml0KHByc19tYXRfZmVtYWxlLCBjb3ZfbWF0X2ZlbWFsZSwgbXZhbHVlc19mZW1hbGUpCnNhdmUobGlzdD1jKCJ0b3BfcHJzX2hpdHMiLCJ0b3BfbWFsZV9wcnNfaGl0cyIsInRvcF9mZW1hbGVfcHJzX2hpdHMiKSxmaWxlPSJwcnNfbmFsbHNfY3Jvc3Nfd19zZXhfc3RyYXRpZmllZC5SRGF0YSIpCmBgYAoKYGBge3J9Cm1hbmlmZXN0IDwtIElsbHVtaW5hSHVtYW5NZXRoeWxhdGlvbkVQSUNhbm5vLmlsbTEwYjQuaGcxOTo6T3RoZXIgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAibmFtZSIpCnByc19hbm5vdCA8LSBkYXRhLnRhYmxlKHRvcF9wcnNfaGl0cylbbWFuaWZlc3QsIGdlbmUgOj0gZ3N1YigiOy4qIiwgIiIsIFVDU0NfUmVmR2VuZV9OYW1lKSwgb24gPSBjKElEID0gIm5hbWUiKV0KcHJzX2Fubm90X21hbGUgPC0gZGF0YS50YWJsZSh0b3BfbWFsZV9wcnNfaGl0cylbbWFuaWZlc3QsIGdlbmUgOj0gZ3N1YigiOy4qIiwgIiIsIFVDU0NfUmVmR2VuZV9OYW1lKSwgb24gPSBjKElEID0gIm5hbWUiKV0KcHJzX2Fubm90X2ZlbWFsZTwtIGRhdGEudGFibGUodG9wX2ZlbWFsZV9wcnNfaGl0cylbbWFuaWZlc3QsIGdlbmUgOj0gZ3N1YigiOy4qIiwgIiIsIFVDU0NfUmVmR2VuZV9OYW1lKSwgb24gPSBjKElEID0gIm5hbWUiKV0KcGxvdF9wcnNfaGl0cyA8LSBmdW5jdGlvbihwcnNfYW5ub3QsbGFiZWxfY29sb3IpewogIGdncGxvdChwcnNfYW5ub3QsIGFlcyhsb2dGQywgLWxvZzEwKFAuVmFsdWUpKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fcG9pbnQoCiAgICAgIGRhdGEgPSBzdWJzZXQocHJzX2Fubm90LCBhZGouUC5WYWwgPCAwLjA1ICYgYWJzKGxvZ0ZDKSA+IDAuMDMpLAogICAgICBjb2xvciA9IGxhYmVsX2NvbG9yLAogICAgICBtYXBwaW5nID0gYWVzKGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSkpCiAgICApICsKICAgIGdlb21faGxpbmUoCiAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICAgIHlpbnRlcmNlcHQgPSBtaW4oLWxvZzEwKHByc19hbm5vdCRQLlZhbHVlW3Byc19hbm5vdCRhZGouUC5WYWwgPCAwLjA1XSkpCiAgICApICsKICAgIGdlb21fdmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIiwgeGludGVyY2VwdCA9IDAuMDMpICsKICAgIGdlb21fdmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIiwgeGludGVyY2VwdCA9IC0wLjAzKSArCiAgICBnZW9tX3RleHRfcmVwZWwoCiAgICAgIGRhdGEgPSBwcnNfYW5ub3QgJT4lIGZpbHRlcihhYnMobG9nRkMpID4gMC4wMyAmIGFkai5QLlZhbCA8IDAuMDUpLAogICAgICBjb2xvciA9ICJkb2RnZXJibHVlIiwKICAgICAgbWFwcGluZyA9IGFlcyhsb2dGQywgLWxvZzEwKFAuVmFsdWUpLCBsYWJlbCA9IGlmZWxzZShnZW5lICE9ICIiLCBnZW5lLCBJRCkpLAogICAgICBzaXplID0gMywKICAgICAgbWF4Lm92ZXJsYXBzID0gMjAKICAgICkgKwogICAgbGFicyh5ID0gYnF1b3RlKCJsb2ciWzEwXSB+ICIoUCkiKSwgeCA9IHF1b3RlKERlbHRhIH4gIk0iIH4gTWV0aHlsYXRpb24pKSArCiAgICB0aGVtZV9taW5pbWFsKCkKfQoKcGxvdF9wcnNfaGl0cyhwcnNfYW5ub3QsImdyYXk0MCIpCnBsb3RfcHJzX2hpdHMocHJzX2Fubm90X21hbGUsImxpZ2h0Ymx1ZSIpCnBsb3RfcHJzX2hpdHMocHJzX2Fubm90X2ZlbWFsZSwicGluayIpCmBgYAoKCgojIE1hbmhhdHRhbiBwbG90IHZzIEdXQVMgbWFuaGF0dGFuIHBsb3QKYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShxcW1hbikKY3BnX3BvcyA8LSBJbGx1bWluYUh1bWFuTWV0aHlsYXRpb25FUElDYW5uby5pbG0xMGI0LmhnMTk6OkxvY2F0aW9ucyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJuYW1lIikKY29weV9hbm5vdCA8LSBwcnNfYW5ub3RbY3BnX3Bvcywgb24gPSBjKElEID0gIm5hbWUiKV0gJT4lCiAgbXV0YXRlKGNociA9IGFzLm51bWVyaWMocmVjb2RlKGdzdWIoImNociIsICIiLCBjaHIpLFg9IjIzIixZPSIyNCIpKSkKdG9fcGxvdCA8LSBjb3B5X2Fubm90WywgLihTTlAgPSBnZW5lLCBDSFIgPSBjaHIsIEJQID0gcG9zLCBQID0gUC5WYWx1ZSwgRkRSID0gYWRqLlAuVmFsKV1bIWlzLm5hKFApXQptYW5oYXR0YW4odG9fcGxvdCwKICBhbm5vdGF0ZVB2YWwgPSBtYXgodG9fcGxvdFtGRFIgPCAwLjA1XSRQKSwKICBhbm5vdGF0ZVRvcCA9IFRSVUUsCiAgZ2Vub21ld2lkZWxpbmUgPSBtaW4oLWxvZzEwKHRvX3Bsb3RbRkRSIDwgMC4wNV0kUCkpLAogIHN1Z2dlc3RpdmVsaW5lID0gRkFMU0UKKQptYW5oYXR0YW4odG9fcGxvdFtDSFIgPT0gMTddLAogIGFubm90YXRlUHZhbCA9IG1heCh0b19wbG90W0ZEUiA8IDAuMDVdJFApLAogIGFubm90YXRlVG9wID0gRkFMU0UsCiAgZ2Vub21ld2lkZWxpbmUgPSBtaW4oLWxvZzEwKHRvX3Bsb3RbRkRSIDwgMC4wNV0kUCkpLAogIHN1Z2dlc3RpdmVsaW5lID0gRkFMU0UKKQpxcSh0b19wbG90JFApCmBgYAoKYGBge3IsZXZhbD1GQUxTRX0KR1dBUyA8LSBmcmVhZCgifi9uYWxsc19QRC5RQy5neiIpCgptYW5oYXR0YW4oR1dBUywKICBhbm5vdGF0ZVB2YWwgPSA1ZS04LAogIGJwID0gIlBPUyIsCiAgcCA9ICJwIiwKICBzdWdnZXN0aXZlbGluZSA9IEZBTFNFCikKYGBgCgoKCiMjIERNUnMKCmBgYHtyfQpsaWJyYXJ5KERNUmNhdGUpClM0X3RvX2RhdGFmcmFtZSA8LSBmdW5jdGlvbihzNG9iaikgewogIG5tcyA8LSBzbG90TmFtZXMoczRvYmopCiAgbHN0IDwtIGxhcHBseShubXMsIGZ1bmN0aW9uKG5tKSBzbG90KHM0b2JqLCBubSkpCiAgYXMuZGF0YS5mcmFtZShzZXROYW1lcyhsc3QsIG5tcykpCn0KcnVuX2RtcmNhdGUgPC0gZnVuY3Rpb24ocHJzX21hdCxjb3ZfbWF0LG12YWx1ZXMpewogIGRlc2lnbl9wcnMgPC0gbW9kZWwubWF0cml4KH4uLCBkYXRhID0gY2JpbmQocHJzX21hdFssIGBQdF81ZS0wOGBdLCBjb3ZfbWF0KSkKICBwcnNfYW5ub3RhdGVkIDwtIGNwZy5hbm5vdGF0ZShkYXRhdHlwZSA9ICJhcnJheSIsIG9iamVjdCA9IG12YWx1ZXMsIGFuYWx5c2lzLnR5cGUgPSAiZGlmZmVyZW50aWFsIiwgZGVzaWduID0gZGVzaWduX3BycywgY29lZiA9IDIsIHdoYXQgPSAiTSIsIGFycmF5dHlwZSA9ICJFUElDIiwgZmRyID0gMC4wNSkKICBwcnNfZG1yX3JlcyA8LSBkbXJjYXRlKHByc19hbm5vdGF0ZWQsIGxhbWJkYSA9IDEwMDAsIEMgPSAyKQogIHJldHVybihTNF90b19kYXRhZnJhbWUocHJzX2Rtcl9yZXMpKQp9CmRtcl9jcm9zcyA8LSBydW5fZG1yY2F0ZShwcnNfbWF0LCBjb3ZfbWF0LCBtdmFsdWVzKQpkbXJfbWFsZXMgPC0gcnVuX2RtcmNhdGUocHJzX21hdF9tYWxlLGNvdl9tYXRfbWFsZSxtdmFsdWVzX21hbGUpCmRtcl9mZW1hbGUgPC0gcnVuX2RtcmNhdGUocHJzX21hdF9mZW1hbGUsY292X21hdF9mZW1hbGUsbXZhbHVlc19mZW1hbGUpCmBgYApgYGB7cn0KYW5ub3RhdGlvbiA8LSBtaW5maTo6Z2V0QW5ub3RhdGlvbihJbGx1bWluYUh1bWFuTWV0aHlsYXRpb25FUElDYW5uby5pbG0xMGI0LmhnMTkpCmBgYAojIyMgUGxvdHRpbmcgYWxsIERNUnMgey50YWJzZXQgLnRhYnNldC1mYWRlfQpgYGB7cn0KZ2V0X2Rtcl9lZmZlY3RzIDwtIGZ1bmN0aW9uKGRtciwgbGltbWFfcmVzLG12YWx1ZXMpIHsKICBkbXJfY29vcmQgPC0gc3RyX21hdGNoX2FsbChhcy5jaGFyYWN0ZXIoZG1yKSwgIihjaHIuKik6KFswLTldKiktKFswLTldKikiKVtbMV1dCiAgY3BncyA8LSBhcy5kYXRhLnRhYmxlKGFubm90YXRpb25bYW5ub3RhdGlvbiRjaHIgPT0gZG1yX2Nvb3JkWzJdICYgYW5ub3RhdGlvbiRwb3MgPj0gYXMubnVtZXJpYyhkbXJfY29vcmRbM10pICYgYW5ub3RhdGlvbiRwb3MgPD0gYXMubnVtZXJpYyhkbXJfY29vcmRbNF0pLCBdKQogIHJlcyA8LSBsaW1tYV9yZXNbY3Bncyxvbj1jKCJJRCI9Ik5hbWUiKSxub21hdGNoPTAgXQogIGRtcl8xIDwtIGFzLmRhdGEuZnJhbWUocmVzWyFpcy5uYShyZXMkbG9nRkMpLCBdKQogIGRtcl9tZXRoeSA8LSByZXNoYXBlMjo6bWVsdChsdW1pOjptMmJldGEobXZhbHVlc1tkbXJfMSRJRCwgXSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICB0b19wbG90IDwtIG1lcmdlKGRtcl8xLCBkbXJfbWV0aHksIGJ5LnggPSAiSUQiLCBieS55ID0gIlZhcjEiKQogIHRvX3Bsb3QkRE1SIDwtIGRtcgogIHRvX3Bsb3QKfQpnZXRfZG1yX3JlcyA8LSBmdW5jdGlvbihkbXIsIGxpbW1hX3JlcykgewogIGRtcl9jb29yZCA8LSBzdHJfbWF0Y2hfYWxsKGFzLmNoYXJhY3RlcihkbXIpLCAiKGNoci4qKTooWzAtOV0qKS0oWzAtOV0qKSIpW1sxXV0KICBjcGdzIDwtIGFubm90YXRpb25bYW5ub3RhdGlvbiRjaHIgPT0gZG1yX2Nvb3JkWzJdICYgYW5ub3RhdGlvbiRwb3MgPj0gYXMubnVtZXJpYyhkbXJfY29vcmRbM10pICYgYW5ub3RhdGlvbiRwb3MgPD0gYXMubnVtZXJpYyhkbXJfY29vcmRbNF0pLCBdCiAgcmVzIDwtIGNiaW5kKGNwZ3MsIGxpbW1hX3Jlc1tjcGdzJE5hbWUsIF0pCiAgcmVzJERNUiA8LSBkbXIKICByZXR1cm4ocmVzKQp9CnBsb3RfZG1ycyA8LSBmdW5jdGlvbihkbXJfcmVzLGxpbW1hX3JlcyxwcnNfbWF0LCBtdmFsdWVzLCBjYXNlX2NvbnRyb2wpIHsKICB0b19wbG90IDwtIHJiaW5kbGlzdChsYXBwbHkoZG1yX3JlcyRjb29yZCwgZnVuY3Rpb24oZG1yKSBnZXRfZG1yX2VmZmVjdHMoZG1yLCBsaW1tYV9yZXMsbXZhbHVlcykpKSAlPiUKICAgIG11dGF0ZShTQ09SRTFfQVZHID0gc2NhbGUocHJzX21hdFttYXRjaChWYXIyLElEcyRJSUQpLGBQdF81ZS0wOGBdKSxQRCA9IFBEW21hdGNoKFZhcjIsSUlEKV0kUEQpICU+JQogICAgZmlsdGVyKCFpcy5uYShTQ09SRTFfQVZHKSkKICBmb3IoY3VyX2RtciBpbiB1bmlxdWUodG9fcGxvdCRETVIpKXsKICAgIGN1cl9wbG90IDwtIHRvX3Bsb3RbRE1SID09IGN1cl9kbXJdCiAgICBwMSA8LSBnZ3Bsb3QoY3VyX3Bsb3QgLCBhZXMocG9zLCB2YWx1ZSwgY29sb3IgPSBTQ09SRTFfQVZHKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSByZXYoY2FzZV9jb250cm9sKVsxXSwgaGlnaCA9IHJldihjYXNlX2NvbnRyb2wpWzJdKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIGxhYnModGl0bGUgPSB1bmlxdWUoY3VyX3Bsb3QkRE1SKSx4PSJQT1MiLHk9YnF1b3RlKCJNZXRoeWxhdGlvbiJ+YmV0YSksY29sb3IgPSAiTm9ybWFsaXplZCBQRCBQUlMiKSsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCiAgICBwMiA8LSBnZ3Bsb3QoY3VyX3Bsb3QgJT4lIG11dGF0ZShQRCA9IGlmZWxzZShQRCA9PSAxLCAiQ0FTRSIsICJDT05UUk9MIikpLCBhZXMoZmFjdG9yKHBvcyksIHZhbHVlLCBjb2xvciA9IFBEKSkgKwogICAgICBnZW9tX2JveHBsb3QocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjc1KSkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2FzZV9jb250cm9sKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBQRCksIGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIpICsKICAgICAgbGFicyh0aXRsZSA9IHVuaXF1ZShjdXJfcGxvdCRETVIpLHg9IlBPUyIseT1icXVvdGUoIk1ldGh5bGF0aW9uIn5iZXRhKSxjb2xvciA9ICJQRCBzdGF0dXMiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQogICAgcHJpbnQocDEpCiAgICBwcmludChwMikKICB9Cn0KCnBsb3RfZG1ycyhkbXJfY3Jvc3MsIHByc19hbm5vdCwgcHJzX21hdCxtdmFsdWVzLCByZXYoYygiZ3JheTgwIiwgImdyYXk0MCIpKSkKcGxvdF9kbXJzKGRtcl9tYWxlcyxwcnNfYW5ub3RfbWFsZSxwcnNfbWF0X21hbGUsIG12YWx1ZXNfbWFsZSxyZXYoYygibGlnaHQgYmx1ZSIsICJsaWdodGJsdWU0IikpKQpwbG90X2RtcnMoZG1yX2ZlbWFsZSwgcHJzX2Fubm90X2ZlbWFsZSwgcHJzX21hdF9mZW1hbGUsIG12YWx1ZXNfZmVtYWxlLHJldihjKCJsaWdodHBpbmsiLCAibGlnaHRwaW5rNCIpKSkKYGBgCgoKYGBge3J9CmRtcl9jcm9zcwpkbXJfbWFsZXMKZG1yX2ZlbWFsZQpgYGAK